# -*- coding: utf-8 -*-
from __future__ import absolute_import

import re

from PyQt4.QtGui import QPlainTextEdit
import time
from PyQt4.QtGui import QTextCursor
from PyQt4.QtGui import QTextCharFormat
from PyQt4.QtCore import Qt
from PyQt4.QtCore import QProcess
from PyQt4.QtCore import SIGNAL

from ninja_ide.core import settings
from ninja_ide.core import file_manager
from ninja_ide.tools import styles
from ninja_ide.gui.main_panel import main_container


class RunWidget(QPlainTextEdit):

    def __init__(self):
        QPlainTextEdit.__init__(self)
        self.setReadOnly(True)
        styles.set_style(self, 'editor')
        #traceback pattern
        self.patLink = re.compile(r'(\s)*File "(.*?)", line \d.+')
        #formats
        self.plain_format = QTextCharFormat()
        self.error_format = QTextCharFormat()
        self.error_format.setAnchor(True)
        self.error_format.setFontUnderline(True)
        self.error_format.setUnderlineStyle(QTextCharFormat.SingleUnderline)
        self.error_format.setUnderlineColor(Qt.red)
        self.error_format.setForeground(Qt.blue)
        self.error_format.setToolTip(self.tr("Click to show the source"))
        #process
        self._proc = QProcess(self)
        self.connect(self._proc, SIGNAL("readyReadStandardOutput()"),
            self._refresh_output)
        self.connect(self._proc, SIGNAL("readyReadStandardError()"),
            self._refresh_error)
        self.connect(self, SIGNAL("blockCountChanged(int)"),
            self._scroll_area)

    def _scroll_area(self):
        self.moveCursor(QTextCursor.End)

    def start_process(self, fileName, pythonPath=False, programParams=''):
        self.setPlainText('Running: %s (%s)\n\n' % (fileName,
            unicode(time.ctime())))
        self.moveCursor(QTextCursor.Down)
        self.moveCursor(QTextCursor.Down)
        self.moveCursor(QTextCursor.Down)

        #runner.run_code_from_file(fileName)
        if not pythonPath:
            pythonPath = settings.PYTHON_PATH
        #change the working directory to the fileName dir
        file_directory = file_manager.get_folder(fileName)
        self._proc.setWorkingDirectory(file_directory)
        #force python to unbuffer stdin and stdout
        options = ['-u'] + settings.EXECUTION_OPTIONS.split()
        self._proc.start(pythonPath, options + [fileName] + \
            [p.strip() for p in programParams.split(',') if p])

    def mousePressEvent(self, event):
        QPlainTextEdit.mousePressEvent(self, event)
        self.go_to_error(event)

    def kill_process(self):
        self._proc.kill()
        self.textCursor().insertText('\n\n' + self.tr("Execution Interrupted"))

    def _refresh_output(self):
        #we should decode the bytes!
        text = self._proc.readAllStandardOutput().data().decode('utf8')
        self.textCursor().insertText(text)

    def _refresh_error(self):
        #we should decode the bytes!
        cursor = self.textCursor()
        text = self._proc.readAllStandardError().data().decode('utf8')
        text_lines = text.split('\n')
#        print "Lineas: %s" % text_lines
        for t in text_lines:
            cursor.insertBlock()
            if self.patLink.match(t):
                cursor.insertText(t, self.error_format)
            else:
                cursor.insertText(t, self.plain_format)

    def go_to_error(self, event):
        cursor = self.cursorForPosition(event.pos())
        text = cursor.block().text()
        if self.patLink.match(text):
            file_path, lineno = self._parse_traceback(unicode(text))
            main = main_container.MainContainer()
            main.open_file(file_path)
            main.editor_jump_to_line(lineno=int(lineno)-1)

    def _parse_traceback(self, text):
        """
        Parse a line of python traceback and returns
        a tuple with (file_name, lineno)
        """
        file_word_index = text.find('File')
        comma_min_index = text.find(',')
        comma_max_index = text.rfind(',')
        file_name = text[file_word_index+6:comma_min_index-1]
        lineno = text[comma_min_index+7:comma_max_index]
        return (file_name, lineno)
